/**
 * ...
 * @author Cref
 */

package activex;

extern class Collection<T> {
	//Returns a long value that is the number of items in the collection.
	//The counting starts at zero. You can use this value to loop throught the collection by iterating from zero to the value of Count minus one. 
  var count(default, null):Int;
	//this way, iterator can be typed while it remains possible to extend on this class
	inline var iterator(getIterator, never):Void->Iterator<T>;
	private inline function getIterator():Void->Iterator<Dynamic> return Helper.getIterator(this)
	//this is how it SHOULD work:
	//inline function iterator():Iterator<T> return new Helper(this)
}

//NOTE: extends Collection<String>, not extends Collection<T> !!!
extern class AssociativeCollection<T> extends Collection<String> {
	/**
	 * The Item property is used to return a specific member of the Collection. 
	 * @param	index		Can be the named item or the position (ordinal) number.
	 * @return
	 */
  @:multitype function item(?key:String,?index : Int):T;
	//public inline function itemAt(index : Int) : T return item(untyped index)
}

extern class WritableAssociativeCollection<T> extends AssociativeCollection<T> {
  function remove(key:String):Void;
  function removeAll():Void;
	//this way, write can be typed while it remains possible to extend on this class
	inline var write(getWriter, never):String->T->Void;
	private inline function getWriter():String->Dynamic->Void return Helper.getWriter(this)
	//inline function write(key:String,value:Dynamic):Void js.jscript.CollectionHelper.write(this,key,value)
}

/**
 * wraps an Enumerator as an Iterator
 * @author Cref
 */
private class Helper {
	public static function getWriter(col:WritableAssociativeCollection<Dynamic>):String->Dynamic->Void
		return function(key:String, value:Dynamic):Void untyped __js__("col(key)=value")
	
	public static function getIterator(col:Collection<Dynamic>):Void->Iterator<Dynamic>
		return function() return new Helper(col)
	
  var _enum:Enumerator<Dynamic>;

  public function new(coll:Collection<Dynamic>)
		_enum=new Enumerator<Dynamic>(coll)
  
  public function hasNext():Bool
		return !_enum.atEnd()
  
  public function next() {
		var r=_enum.item();
		_enum.moveNext();
		return r;
  }
	
	//workaround for the way values are written in JScript
	//inheritance using generics doesn't work well together with inlined functions :(
	//when a type parameter is used in a method, the compiler doesn't look further up the inheritence chain
	//then the class in which the inline function is declared.
	//and inline functions can not be overridden!
	//One solution is to use Dynamic instead of the actual type parameters for inline functions.
	//A better solution for now is not to use 'inline' and solve the problem with 'using'.
	//The downside to that is that we need to add the 'using' statement to every class that needs the function.
	/*
  inline function write(key:String, value:T):Void {
		_write(this,key,value);
  }
	public static function write<T>(coll:WritableAssociativeCollection<T>,key:String,value:T):Void {
		untyped __js__("coll(key)=value");
	}
	uses JScript's Enumerator to iterate over the collection.
	allows easy iteration of collections using the for keyword.
	Unfortunately, a bug in haXe prevents us from using this behaviour properly:
	Inherited inline iterator functions only work when explicitly called.
	omitting the call in a for-statement generates a $closure() call.
	example:
	for (n in Request.queryString) becomes:
	{var $it3=$closure(Request.queryString,"iterator")();
	for (n in Request.queryString.iterator()) becomes:
	{var $it3=new hxtc.CollectionIterator(Request.queryString);
	PLUS!
	inlined functions do not work with type parameters when inherited :(
	public static function iterator<T>(coll:Collection<T>):CollectionHelper<T> {
		return new CollectionHelper(coll);
	}
	*/

}